#pragma once

#include "FXValue.h"
#include "math.h"
/**
* Wrapper around a float3 (x,y,z)
* @author Koen Samyn
*/
class DAEFloat3: public FXValue
{
public:
	/**
	* Creates a new DAEFloat3 object, with the
	* members initialized to 0.
	*/
	DAEFloat3();
	/**
	* Creates a new DAEFloat3 object.
	* @param xValue the initial x value.
	* @param yValue the initial y value.
	* @param zValue the initial z value.
	*/
	DAEFloat3(float xValue, float yValue, float zValue);
	/**
	* Creates a new DAEFloat3 object.
	* @param xValue the initial x value.
	* @param yValue the initial y value.
	* @param zValue the initial z value.
	* @param normalize if true the DAEFloat3 object will be normalized
	* immediatly, if false the x,y & z values will not be transformed.
	*/
	DAEFloat3(float xValue, float yValue, float zValue,bool normalize);
	/**
	* DAEFloat3 is a value object, overloading the = operator
	* is necessary.
	*/
	DAEFloat3& operator=(const DAEFloat3& float3);
	/**
	* DAEFloat3 is a value object,overloading the copy constructor
	* is necessary.
	* @param float3 the float3 object to copy.
	*/
	DAEFloat3(const DAEFloat3& float3);
	/**
	* Sets the 3 values of the DAEFloat3 object in one go.
	* @param x the new x value.
	* @param y the new y value.
	* @param z the new z value.
	*/
	inline void SetValues(float x, float y, float z)
	{
		this->x = x;
		this->y = y;
		this->z = z;
	}
	/**
	* Copies the values from another DAEFloat3 object.
	* @param toCopy the DAEFloat3 object to copy.
	*/
	inline void SetValues(DAEFloat3& toCopy){
		this->x = toCopy.x;
		this->y = toCopy.y;
		this->z = toCopy.z;
	}
	/**
	* Normalizes this DAEFloat3 object.
	* WARNING : this method changes the internal state.
	*/
	inline void Normalize();
	/**
	* Returns the length of this DAEFloat3 object.
	* @return the lenght of this DAEFloat3 object.
	*/
	inline float Length() const { return sqrt( x*x + y*y + z*z );}
	/**
	* The Squared length of this DAEFloat3 object.
	* Can be used to compare lengths of different DAEFloat3 objects,
	* in other when it is not needed to calculate the squared length.
	* @return the squared length of this DAEFloat3 object.
	*/
	inline float SquaredLength() const{ return x*x+y*y+z*z;}
	/**
	* Implements the formula : result = this + position.
	* This method does not change the internal data.
	* @param position the vector to add to this vector.
	* @param outResult stores the result of the add operation.
	* @return the DAEFloat3 result object.
	*/ 
	DAEFloat3& Add( DAEFloat3& outResult, const DAEFloat3& position) const;
	/**
	* Implements the formula : result = this - vector.
	* This method does not change the internal data.
	* @param position the vector to subtract from this vector.
	* @param outResult stores the result of the subtract operation.
	* @return the DAEFloat3 result object.
	*/
	DAEFloat3& Subtract(DAEFloat3& outResult,const DAEFloat3& position) const;
	/**
	* Implements the formula : 
	* 1) result = to - this
	* 2) normalize(result)
	* @param to the position the result vector will point at.
	* @param outResult stores the result of the create vector operation.
	* @return the normalized vector between to and this.
	*/
	DAEFloat3& CreateVector(DAEFloat3& outResult, const DAEFloat3& to) const;
	/**
	* Creates a vector that is perpendicular to this vector.
	* @param outResult the resulting vector.
	* @param normalizeResult set this to true if the result should be normalized.
	*/
	void CreatePerpendicularVector(DAEFloat3& outResult) const;
	/**
	* Implements the formula :
	* 1) result = cross(this,vector);
	* @param vector the vector to calculate the cross product for.
	* @param outResult stores the result of the cross operation.
	* @return the resulting cross product.
	*/
	DAEFloat3& Cross(DAEFloat3& outResult,const DAEFloat3& vector) const;
	/**
	* Implements the formula :
	* 1) result = cross(this,vector);
	* 2) normalize(result)
	* @param vector the vector to calculate the cross product for.
	* @param outResult stores the result of the cross and normalize operation.
	* @return the resulting cross product.
	*/
	DAEFloat3& CrossAndNormalize(DAEFloat3& outResult,const DAEFloat3& vector) const;
	/**
	* Computes the dot product with another DAEFloat3 object.
	* @param vector2 the second operand in the dot product.
	* @return the dot product.
	*/
	float Dot( const DAEFloat3& vector2) const;
	/**
	* Implements the formula : result = this + scale*vector
	* @param outResult stores the result of the Add operation.
	* @param scale the scale of the vector.
	* @param vector the vector to add to this vector.
	*/
	DAEFloat3& Add(DAEFloat3& outResult,const float scale, const DAEFloat3& vector) const;
	/**
	* Scales this DAE3Float object and returns the result.
	* result = this*scale;
	* @param outResult stores the result of the scale operation.
	* @float scale the value of the multiplier
	*/
	DAEFloat3& Scale(DAEFloat3& outResult, const float scale) const;
	/**
	* Clamps the values in this DAEFloat3 object to the specified
	* range.
	* @param min the minimum value for the x,y and z members.
	* @param max the maximum value for the x,y and z members.
	*/
	void Clamp(float min, float max);
	/**
	* Returns the size of the value in bytes.
	* @return the size in bytes.
	*/
	virtual int GetSizeInBytes() const{
		return 3*sizeof(float);
	}
	/**
	* Returns the pointer to the beginning of the value.
	* @return a void pointer to the beginning of the value.
	*/
	virtual const void* GetValuePointer() const{
		return &x;
	}

	/**
	* Operators
	*/
	const DAEFloat3 operator-(const DAEFloat3& op2) const{
		return DAEFloat3( x - op2.x, y - op2.y, z - op2.z);
	}

	const DAEFloat3 operator+(const DAEFloat3& op2) const{
		return DAEFloat3( x + op2.x, y + op2.y, z + op2.z);
	}
	
	DAEFloat3& operator+=(const DAEFloat3& op2) {
		this->SetValues(x+op2.x,y+op2.y,z+op2.z);
		return *this;
	}

	DAEFloat3& operator/=(const float scale){
		this->SetValues(x/scale,y/scale,z/scale);
		return *this;
	}

	const DAEFloat3 operator*(const float scale) const{
		return DAEFloat3( x*scale, y*scale, z*scale);
	}

	const DAEFloat3 operator/(const float scale) const{
		return DAEFloat3( x/scale, y/scale, z/scale);
	}

	/**
	* Calculates the barycentric coordinates of the point p given the
	* triangle as defined by p1, p2 & p3.
	* @param p the point to convert to barycentric coordinates.
	* @param p1 the first vertex of the triangle.
	* @param p2 the second vertex of the triangle.
	* @param p3 the third vertex of the triangle.
	* @return the barycentric coordinates of the point p.
	*/
	static DAEFloat3 BarycentricCoordinates(DAEFloat3& p, DAEFloat3& p1, DAEFloat3& p2, DAEFloat3& p3);

	/**
	* The DAEFloat3 members
	*/
	float x,y,z;

private:
	
	
};
